/*
 * CodeTree.java
 *
 * Created on 26. Dezember 2007, 18:34
 */
package de.blitzcoder.collide.gui.codetree;

// Imports
import de.blitzcoder.collide.Interface;
import de.blitzcoder.collide.engine.parser.CodeConstant;
import de.blitzcoder.collide.engine.parser.CodeField;
import de.blitzcoder.collide.engine.parser.CodeFunction;
import de.blitzcoder.collide.engine.parser.CodeGlobal;
import de.blitzcoder.collide.engine.parser.CodeMethod;
import de.blitzcoder.collide.engine.parser.CodeObject;
import de.blitzcoder.collide.engine.parser.CodeParameter;
import de.blitzcoder.collide.engine.parser.CodeParameterObject;
import de.blitzcoder.collide.engine.parser.CodeType;
import de.blitzcoder.collide.engine.parser.CodeVariable;
import de.blitzcoder.collide.gui.CodeDocument;
import de.blitzcoder.collide.gui.Document;
import de.blitzcoder.collide.gui.IconTreeNode;
import de.blitzcoder.collide.gui.IconTreeRenderer;
import javax.swing.tree.*;
import java.util.LinkedList;
import de.blitzcoder.collide.util.Log;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ListIterator;
import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import de.blitzcoder.collide.icons.Icon;

/**
 *
 * @author blitzcoder
 */
public class Tree extends JTree {

    // Gadgets
    private DefaultMutableTreeNode rootNode;

    // Icons
    private static ImageIcon ICON_BMAX = Icon.load("file_bmax.png");
    private static ImageIcon ICON_CONSTANT = Icon.load("tree_constant.png");
    private static ImageIcon ICON_GLOBAL = Icon.load("menu/website.png");
    private static ImageIcon ICON_FUNCTION = Icon.load("tree_function.png");
    private static ImageIcon ICON_TYPE = Icon.load("tree_type.png");
    private static ImageIcon ICON_FIELD = Icon.load("tree_field.png");
    private static ImageIcon ICON_METHOD = Icon.load("tree_method.png");
    private static ImageIcon ICON_ITEM = Icon.load("tree_item.png");
    private static ImageIcon ICON_FOLDER = Icon.load("tree_singletype.png");

    /*
     * Mouse listener
     */
    private class MouseListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            int selRow = getRowForLocation(e.getX(), e.getY());
            TreePath selPath = getPathForLocation(e.getX(), e.getY());
            if (selRow != -1) {
                if (e.getClickCount() == 2) {
                    if (selPath.getLastPathComponent() instanceof DefaultMutableTreeNode) {
                        doubleClick((DefaultMutableTreeNode) selPath.getLastPathComponent());
                    }
                }
            }
        }

        public void mouseMoved(MouseEvent ev) {
            int selRow = getRowForLocation(ev.getX(), ev.getY());
            TreePath selPath = getPathForLocation(ev.getX(), ev.getY());
            if (selRow != -1) {
                if (selPath.getLastPathComponent() instanceof DefaultMutableTreeNode) {
                    showToolTip((DefaultMutableTreeNode) selPath.getLastPathComponent());
                }
            }
        }
    }

    /** Creates a new instance of CodeTree */
    public Tree() {

        Log.log("creating Interface");

        // Create the tree and set the root node
        rootNode = new DefaultMutableTreeNode("Code");
        setModel(new DefaultTreeModel(rootNode));


        setCellRenderer(new IconTreeRenderer());


        addMouseListener(new MouseListener());
        addMouseMotionListener(new MouseListener());

        fill(new LinkedList<CodeObject>());
    }

    /*
     * Is called when a double-click occours
     */
    private void doubleClick(DefaultMutableTreeNode node) {
        Object userObject = node.getUserObject();
        Log.log("DoubleClick");
        if (userObject != null && userObject instanceof CodeObject) {

            Document doc = Interface.getDocumentManager().getCurrentDocument();

            if (doc instanceof CodeDocument) {
                CodeDocument codeDoc = (CodeDocument) doc;
                codeDoc.selectLine(((CodeObject) userObject).getLine());
            }

        }
    }

    private void showToolTip(DefaultMutableTreeNode node) {
        if (node != null && node.getUserObject() instanceof CodeObject) {
            CodeObject obj = (CodeObject) node.getUserObject();

            String text = "<html>";
            text += "<b>" + obj.getName() + "</b>";
            if (obj instanceof CodeVariable) {
                text += ":" + ((CodeVariable) obj).getType();
                String value = ((CodeVariable) obj).getValue();
                if (value != null && value.length() != 0) {
                    text += " = " + value;
                }
            }
            if (obj instanceof CodeParameterObject) {
                text += ":" + ((CodeParameterObject) obj).getType();
            }
            text += "<br/>";

            if (obj instanceof CodeParameterObject) {
                text += "<b>(</b><br/>";
                CodeParameterObject obj_ = (CodeParameterObject) obj;
                ListIterator<CodeParameter> it = obj_.getParameters().listIterator();
                while (it.hasNext()) {
                    CodeParameter param = it.next();
                    text += "&nbsp;&nbsp;&nbsp;&nbsp;<b>" + param.getName() + "</b>:" + param.getType();
                    if (!param.getValue().equals("")) {
                        text += "=" + param.getValue();
                    }
                    text += "<br/>";
                }
                text += "<b>)</b>";
            }

            if (obj.getComment() != null && obj.getComment().length() > 0) {
                text += "<br><br>";
                text += "<p color='red'>";
                text += obj.getComment().replace("\n", "<br>");
                text += "</p>";
            }


            text += "</html>";

            setToolTipText(text);

        }
    }

    public void fill(LinkedList<CodeObject> list) {

        // Clear the tree
        rootNode = new IconTreeNode("Code", ICON_BMAX);

        // Create the categories
        IconTreeNode constants = new IconTreeNode("Konstanten", ICON_CONSTANT);
        IconTreeNode globals = new IconTreeNode("Globalen", ICON_GLOBAL);
        IconTreeNode functions = new IconTreeNode("Funktionen", ICON_FUNCTION);
        IconTreeNode types = new IconTreeNode("Typen", ICON_TYPE);

        // Add the categories
        rootNode.add(constants);
        rootNode.add(globals);
        rootNode.add(functions);
        rootNode.add(types);

        // Iterate through the list to add all exept of types
        ListIterator<CodeObject> it = list.listIterator();
        while (it.hasNext()) {
            CodeObject obj = it.next();

            IconTreeNode node = null;

            if (obj instanceof CodeConstant) {
                node = new IconTreeNode(
                        obj.getName() +
                        ":" + ((CodeConstant) obj).getType(), ICON_ITEM);
                constants.add(node);
            }

            if (obj instanceof CodeGlobal) {
                node = new IconTreeNode(
                        obj.getName() +
                        ":" + ((CodeGlobal) obj).getType(), ICON_ITEM);
                globals.add(node);
            }

            if (obj instanceof CodeFunction) {
                node = new IconTreeNode(
                        obj.getName() +
                        ":" + ((CodeFunction) obj).getType(), ICON_ITEM);
                functions.add(node);
            }

            if (node != null) {
                node.setUserObject(obj);
            }

        }

        // now add types
        it = list.listIterator();
        while (it.hasNext()) {
            CodeObject obj = it.next();
            if (obj instanceof CodeType) {

                // Create a node for the type. If filter matches, give the green arrow as icon
                IconTreeNode typeNode = new IconTreeNode(obj.getName(), ICON_FOLDER);

                typeNode.setUserObject(obj);
                types.add(typeNode);


                // Create the categories
                IconTreeNode methods = new IconTreeNode("Methoden", ICON_METHOD);
                IconTreeNode fields = new IconTreeNode("Felder", ICON_FIELD);
                constants = new IconTreeNode("Konstanten", ICON_CONSTANT);
                globals = new IconTreeNode("Globalen", ICON_GLOBAL);
                functions = new IconTreeNode("Funktionen", ICON_FUNCTION);
                typeNode.add(globals);
                typeNode.add(constants);
                typeNode.add(functions);
                typeNode.add(methods);
                typeNode.add(fields);

                // Iterate through type content
                ListIterator<CodeObject> typeIt = ((CodeType) obj).getChildren().listIterator();
                while (typeIt.hasNext()) {

                    CodeObject content = typeIt.next();
                    IconTreeNode node = null;

                    // filer Text is already lower case
                    if (content instanceof CodeMethod) {
                        node = new IconTreeNode(
                                content.getName() +
                                ":" + ((CodeMethod) content).getType(), ICON_ITEM);
                        methods.add(node);
                    } else if (content instanceof CodeField) {
                        node = new IconTreeNode(
                                content.getName() +
                                ":" + ((CodeField) content).getType(), ICON_ITEM);
                        fields.add(node);
                    } else if (content instanceof CodeConstant) {
                        node = new IconTreeNode(
                                content.getName() +
                                ":" + ((CodeConstant) content).getType(), ICON_ITEM);
                        constants.add(node);
                    } else if (content instanceof CodeGlobal) {
                        node = new IconTreeNode(
                                content.getName() +
                                ":" + ((CodeGlobal) content).getType(), ICON_ITEM);
                        globals.add(node);
                    } else if (content instanceof CodeFunction) {
                        node = new IconTreeNode(
                                content.getName() +
                                ":" + ((CodeFunction) content).getType(), ICON_ITEM);
                        functions.add(node);
                    }

                    if (node != null) {
                        node.setUserObject(content);
                    }

                }


            }
        }

        setModel(new DefaultTreeModel(rootNode));

    }
}
